package de.siro.notie_surface;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.os.Bundle;
import android.view.Display;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.view.WindowManager;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

@SuppressLint("NewApi")
public class MainActivity extends Activity implements OnTouchListener {


    private int playPosition = 0;
    private Note playedNote;
    private final Paint LINE = new Paint();
    private final Paint TRANSPARENTNOTE = new Paint();
    private int[] noten = new int[12];
    private int[] frequenzen = new int[4000];
    private Thread pitchDetectorThread;
    private SurfaceThread sft;
    private Img note, note_red, note_blue, note_green, options, trash;
    private Canvas c;
    private List<Note> notes;
    private Note firstnote;
    private boolean first = true;
    private boolean newnote = false;
    private volatile boolean move = false;
    private volatile boolean isScrolling = false;
    private volatile boolean editMode = true;
    private final Object monitor = new Object();
    private int canvasSizeX;
    private int canvasSizeY;
    private float scroll = 0;
    private int anzahl_scroll = 20;
    private int pos = 12;
    private float tempXpos;
    private float tempYpos;
    private float tempscroll = scroll;
    private float tempXnote;
    private float tempYnote;

    private double difference = 3;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN);
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
		Display display = getWindowManager().getDefaultDisplay();
		Point size = new Point();
		display.getSize(size);
		canvasSizeX = size.x;
		canvasSizeY = size.y;

        LINE.setAlpha(255);
        LINE.setColor(Color.WHITE);

        TRANSPARENTNOTE.setAlpha(127);

        note = new Img(this, R.drawable.note, (canvasSizeY / 30 * 4));
        note_red = new Img(this, R.drawable.note_red,
                (canvasSizeY / 30 * 4));
        note_blue = new Img(this, R.drawable.note_blue,
                (canvasSizeY / 30 * 4));
        note_green = new Img(this, R.drawable.note_green,
                (canvasSizeY / 30 * 4));
        options = new Img(this, R.drawable.options,
                (canvasSizeY / 30 * 4));
        trash = new Img(this, R.drawable.trash, (int) (canvasSizeY * 0.09));
        sft = new SurfaceThread(this);
        sft.setOnTouchListener(this);
		setContentView(sft);
		
		//Verfuegbare Frequenzen
		int index = 0;
		noten[index++] = 783;
		noten[index++] = 698;
		noten[index++] = 659;
		noten[index++] = 587;
		noten[index++] = 523;
		noten[index++] = 493;
		noten[index++] = 440;
		noten[index++] = 391;
		noten[index++] = 349;
		noten[index++] = 329;
		noten[index++] = 293;
		noten[index++] = 261;

		//Frequenz --> Position in Array
		for (int i = 1; i < frequenzen.length; i++) {
			for (int j = 0; j < noten.length; j++) {
				if (i < noten[j] + noten[j] * difference / 100
						&& i > noten[j] - noten[j] * difference / 100) {
					frequenzen[i] = j + 1;
					break;
				} else {
					frequenzen[i] = (-1);
				}

			}
		}

	}

	@Override
	protected void onPause() {
		// TODO Auto-generated method stub
		
		super.onPause();
		sft.onPause();

	}

	@Override
	protected void onResume() {
		// TODO Auto-generated method stub
		super.onResume();
		sft.onResume();
		// pitchDetectorThread = new Thread(new PitchDetector(sft));
		// pitchDetectorThread.start();
	}

	public class SurfaceThread extends SurfaceView implements Runnable {

		volatile Thread t = null;
		SurfaceHolder sfHolder = null;
		volatile boolean isActive = false;
		double frequency = 0;

		public SurfaceThread(Context context) {
			super(context);
			sfHolder = getHolder();

			notes = new LinkedList<Note>();

		}

		@Override
		public synchronized void run() {
			while (isActive) {
				try {
					Thread.sleep(5);

				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				if (!sfHolder.getSurface().isValid()) {
					continue;
				}
				c = sfHolder.lockCanvas();
				// System.out.println("Canvashoehe: "+c.getHeight()+" Displayhoehe: "+
				// canvasSizeY);
				// System.out.println("Canvashoehe/30: "+c.getHeight()/30+" Notenhoehe: "+
				// note.img.getHeight());
				
				//Erste Note erzeugen (die Note zum Ziehen)
				if (first) {
					firstnote = new Note(sft, note.img, this.getWidth() / 100
							* 95 - note.img.getWidth() / 2, this.getHeight()
							/ 100 + note.img.getHeight() / 2);
//                    playedNote = new Note(sft, note.img, (playPosition +1)
//                            * note.img.getWidth() * 2, canvasSizeY / 3
//                            + (canvasSizeY / 60 * -1));
                    first = false;
                }


				//Alle Elemente werden gezeichnet
				onDraw(c);

				sfHolder.unlockCanvasAndPost(c);
				// if (!move) {
				// synchronized (monitor) {
				// try {
				// Log.d(null, "Waiting...");
				//
				// monitor.wait();
				//
				// } catch (InterruptedException e) {
				// // TODO Auto-generated catch block
				//
				//
				// }
				// }
				// }

			}

		}

		protected void onDraw(Canvas c) {
			//loesche Bild (kompletten Screen schwarz faerben)
			c.drawARGB(255, 0, 0, 0);
			
			//zeichne die erste Note (die Note zum Ziehen)
			if (editMode) {
				firstnote.onDraw(c, 0);
			}
            //zeichne Optionbutton
            c.drawBitmap(options.img, (canvasSizeX - options.w ),
                    -(options.h / 6), null);


            //Momentan gemessene Frequenz in anzeigen
            c.drawText(Double.toString(frequency), 10, 10, LINE);

			//c.save();
			
			//Alle Linien zeichnen
			drawLines(c);
			
			
			if (!editMode) {


                if (notes.get(playPosition).x + note.img.getWidth() - scroll > canvasSizeX) {
                    System.out.println(scroll);
                    scroll = notes.get(playPosition - 1).x - note.img.getWidth();
                }


                //Momentan gemessene Frequenz in anzeigen
                c.drawText(Double.toString(frequency), 10, 10, LINE);

                //Gespielte Note, in rot und transparent Zeichnen
                if (playedNote != null) {
					playedNote.setBitmap(note_red.img);
                    playedNote.setPaint(TRANSPARENTNOTE);
                    playedNote.onDraw(c, scroll);
                }

				//Noten einfaerben
				//Momentan zu spielende Note: Blau
				//Richtig gespielte Note: Gruen
				//Folgende Noten: Weiss
				for (int i = 0; i < notes.size(); i++) {
					if (i > playPosition)
						notes.get(i).setBitmap(note.img);
					else if (i < playPosition)
						notes.get(i).setBitmap(note_green.img);
					else if (i == playPosition)
						notes.get(i).setBitmap(note_blue.img);
				}
			} else {
				//In EditMode alle Noten weiss einfaerben
				for (int i = 0; i < notes.size(); i++) {
					notes.get(i).setBitmap(note.img);
				}

                //zeichne Mülleimer
                c.drawBitmap(trash.img, (canvasSizeX - trash.w),
                        canvasSizeY - trash.h, null);
            }
            //Alle Noten Zeichnen
			for (int i = 0; i < notes.size(); i++) {

				notes.get(i).onDraw(c, scroll);
			}

			//c.restore();

		}

		protected void drawLines(Canvas c) {

			//Obere Linie wird als Abtrennung gezeichnet
			c.drawLine(0, c.getHeight() / 10, c.getWidth(), c.getHeight() / 10,
                    LINE);


            //Notenlinien werden gezeichnet
            for (int i = 1; i < 6; i++) {
				c.drawLine(0, c.getHeight() / 3 + (c.getHeight() / 30 * i),
						c.getWidth(), c.getHeight() / 3
                                + (c.getHeight() / 30 * i), LINE);
            }

            //Linie fuer Loeschbereich wird gezeichnet
			if (editMode) {
				c.drawLine(0, (float) (c.getHeight() * 0.9), c.getWidth(),
                        (float) (c.getHeight() * 0.9), LINE);
            }

		}

		public void drawPlayedNote(final double best_frequ) {

			frequency = best_frequ;
			//Wenn minimale Amplitute nicht erreicht wird, wird -1 gesendet
			if (frequency > 0) {
				//Gespielte Note erstellen, abhaengige Position von der Frequenz
				if (frequenzen[(int) frequency] != (-1)) {

//                    playedNote.x=(playPosition + 1)
//                            * note.img.getWidth() * 2;
//                    playedNote.y=canvasSizeY / 3
//                            + (canvasSizeY / 60 * frequenzen[(int) frequency]);
                    playedNote = new Note(sft, note.img, (playPosition + 1)
                            * note.img.getWidth() * 2, canvasSizeY / 3
							+ (canvasSizeY / 60 * frequenzen[(int) frequency]));
				}
				//Wenn gespielte Note == richtige Note
                if(playedNote!=null) {
                    if (notes.size() > 0
                            && (int) playedNote.y == (int) notes.get(playPosition).y) {
                        //Naechste Note
                        if (playPosition != notes.size() - 1) {
                            playPosition++;

                        }
                        //Ende erreicht, Beginn von vorne
                        else {
                            playPosition = 0;
                            scroll = 0;
                        }

                    }
                }
			}

		}

		public void onPause() {

			isActive = false;
			pitchDetectorThread.interrupt();
		}

		public void onResume() {
			isActive = true;
			t = new Thread(this);
			t.start();
			editMode = true;

		}

	}

	@Override
	public boolean onTouch(View v, MotionEvent event) {
		// System.out.println("Bildminx: "+(notes.get(0).x
		// -(notes.get(0).note.img.getWidth()/2))
		// +" < Eventpos: "+event.getX()+" < Bildmaxx: "+(notes.get(0).x+(notes.get(0).note.img.getWidth()/2))
		// );
		// System.out.println("BildminY: "+(notes.get(0).y
		// -(notes.get(0).note.img.getHeight()/2))
		// +" < Eventpos: "+event.getY()+" < BildmaxY: "+(notes.get(0).y+(notes.get(0).note.img.getHeight()/2))
		// );
		switch (event.getAction()) {

		case MotionEvent.ACTION_DOWN:

			// synchronized (monitor) {
			// monitor.notify();
			// }
			
			//EditMode starten/beenden
            if (event.getY() < options.h - options.h / 6
                    && event.getX() > canvasSizeX - options.w) {
                if (editMode) {
                    scroll = 0;
                    playPosition = 0;
                    editMode=false;
					pitchDetectorThread = new Thread(new PitchDetector(sft));
					pitchDetectorThread.start();
				}
				else{
					pitchDetectorThread.interrupt();
					editMode=true;
				}
			}
			if (editMode) {
				//Alle Noten loeschen Dialog aufrufen
				if (event.getY() > canvasSizeY * 0.9
						&& event.getX() > canvasSizeX * 0.8) {
					if (notes.size() > 0)
						showdeldialog();

				}

				//Neue Note Anlegen
				if (event.getX() > firstnote.x - note.img.getWidth()
						&& event.getX() < firstnote.x + note.img.getWidth()
						&& event.getY() > firstnote.y - note.img.getHeight()
						&& event.getY() < firstnote.y + note.img.getHeight()
								/ 2) {
					notes.add(new Note(sft, note.img, firstnote.x + scroll,
							firstnote.y));
                    newnote = true;
                }

                //Note verschieben aktivieren
				for (int i = notes.size() - 1; i >= 0; i--) {
					if (event.getX() > (notes.get(i).x
							- notes.get(i).note.getWidth() - scroll)
							&& event.getX() < (notes.get(i).x
									+ notes.get(i).note.getWidth() - scroll)
							&& event.getY() > (notes.get(i).y - notes.get(i).note
									.getHeight())
							&& event.getY() < (notes.get(i).y + notes.get(i).note
									.getHeight() / 2)) {
						tempXnote = notes.get(i).x;
						tempYnote = notes.get(i).y;
						notes.get(i).move = true;

						break;
					}
				}
				//Scrollen aktivieren
				if (event.getY() > canvasSizeY / 3 + (canvasSizeY / 60 * pos)
						+ canvasSizeY / 120) {
					tempXpos = event.getX();
					isScrolling = true;

				}
			}
			break;

		case MotionEvent.ACTION_MOVE:
			if (editMode) {
				for (int i = notes.size() - 1; i >= 0; i--) {
					//Note mit aktivem Move verschieben
					if (notes.get(i).move) {
						notes.get(i).x = event.getX() + scroll;
						
						
						for (int j = 1; j < pos; j++) {
							//Raster fuer die Notenlinien
							if (event.getY() > canvasSizeY / 3
									+ (canvasSizeY / 60 * j) - canvasSizeY
									/ 120
									&& event.getY() < canvasSizeY / 3
											+ (canvasSizeY / 60 * j)
											+ canvasSizeY / 120) {
								notes.get(i).y = canvasSizeY / 3
										+ (canvasSizeY / 60 * j);
							} 
							//Ausserhalb der Notenlinien normal verschieben
							else {
								if (event.getY() < canvasSizeY / 3
										+ (canvasSizeY / 60 * 1) - canvasSizeY
										/ 120
										|| event.getY() > canvasSizeY
												/ 3
												+ (canvasSizeY / 60 * (pos - 1))
												+ canvasSizeY / 120) {
									notes.get(i).y = event.getY();
								}
							}

						}
					}

				}
				
				//Scrollen
				if (notes.size() > 0
						&& isScrolling
						&& event.getY() > canvasSizeY / 3
								+ (canvasSizeY / 60 * pos + 1) + canvasSizeY
								/ 120) {

					if (tempscroll + (tempXpos - event.getX()) < 0) {
						scroll = 0;
					} else {
						if (notes.get(notes.size() - 1).x + note.img.getWidth()
								* anzahl_scroll > canvasSizeX) {
							if (tempscroll + (tempXpos - event.getX()) > (notes
									.get(notes.size() - 1).x - canvasSizeX)
									+ note.img.getWidth() * anzahl_scroll) {
								scroll = (notes.get(notes.size() - 1).x - canvasSizeX)
										+ note.img.getWidth() * anzahl_scroll;
							} else
								scroll = tempscroll + (tempXpos - event.getX());

						}

					}
					// Log.d("scroll", Float.toString(scroll));
				}
			}

			break;
		case MotionEvent.ACTION_UP:
			v.performClick();
			if (editMode) {
				
				//Bewegte Note nach loslassen wieder sperren
				for (int i = 0; i < notes.size(); i++) {
					notes.get(i).move = false;
					//Note im Loeschbereich gezogen --> Note loeschen
					if (notes.get(i).y > canvasSizeY * 0.9) {
						notes.remove(i);
					} 
					else {
						if (notes.get(i).y < canvasSizeY / 3
								+ (canvasSizeY / 60 * 1)
								|| notes.get(i).y > canvasSizeY / 3
										+ (canvasSizeY / 60 * (pos - 1))) {
							//Neu erstellte Note in ungueltigen Bereich --> loeschen
							if (tempYnote < canvasSizeY / 3
									+ (canvasSizeY / 60 * 1)
									|| tempYnote > canvasSizeY / 3
											+ (canvasSizeY / 60 * (pos - 1))) {
								notes.remove(i);
							}
							//Note von gueltigen Bereich in ungueltigen Bereich gezogen --> Alte Position wiederherstellen
							else {
								notes.get(i).x = tempXnote;
								notes.get(i).y = tempYnote;
							}

						}
					}

				}
				//Noten in der Liste nach X-Koordinate sortieren
				Collections.sort(notes);
				
				//Noten auf einheitlichen Abstand bringen
				for (int i = 0; i < notes.size(); i++) {

					notes.get(i).x = (i + 1) * note.img.getWidth() * 2;
				}
				if (!isScrolling && notes.size() > 0) {
					// System.out.println("Scroll: "
					// + (int) (notes.get(notes.size() - 1).x - scroll)
					// + "       Scrollpoint: "
					// + (canvasSizeX - note.img.getWidth()
					// * (anzahl_scroll - 5)));

                    if (newnote) {
                        //Autoscroll mit den eingefuegten Noten
                        if (notes.get(notes.size() - 1).x + note.img.getWidth()
                                * anzahl_scroll > canvasSizeX) {
                            scroll = (notes.get(notes.size() - 1).x - canvasSizeX)
                                    + note.img.getWidth() * anzahl_scroll;
                        }
                        newnote = false;
                    }
                }

                //Scrollen, falls aktiv, deaktivieren
				tempscroll = scroll;
				isScrolling = false;
			}

            break;
        }
		return true;
	}

	//Alle Noten loeschen Dialog
	void showdeldialog() {
		DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				switch (which) {
				case DialogInterface.BUTTON_POSITIVE:
					notes.clear();
                    scroll = 0;
                    break;

				case DialogInterface.BUTTON_NEGATIVE:

					break;
				}
			}
		};

		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setMessage("Moechtest du wirklich ALLE Noten loeschen?")
				.setPositiveButton("Yes", dialogClickListener)
				.setNegativeButton("No", dialogClickListener).show();
	}

}
